From e969e495b8e8b3284bf29d0ebfc6fdc742b3facf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 24 Oct 2014 09:18:19 -0700 Subject: [PATCH] Build examples into `target/examples` This ends up killing two birds with one stone! The rationale behind this is that the example and bin namespaces are not the same, and we don't mix metadata into either filename, so the outputs need to be in different locations. Closes #193 Closes #751 --- src/cargo/core/manifest.rs | 21 +++++++-- src/cargo/ops/cargo_rustc/context.rs | 4 +- src/cargo/ops/cargo_rustc/fingerprint.rs | 6 ++- src/cargo/ops/cargo_rustc/layout.rs | 59 +++++++++++++++--------- src/cargo/ops/cargo_rustc/mod.rs | 6 ++- tests/test_cargo_compile.rs | 16 ++++--- tests/test_cargo_test.rs | 29 ++++++++++++ 7 files changed, 104 insertions(+), 37 deletions(-) diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index e274dbbc2..e2102ac4d 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -104,7 +104,8 @@ impl LibKind { #[deriving(Show, Clone, Hash, PartialEq, Encodable)] pub enum TargetKind { LibTarget(Vec), - BinTarget + BinTarget, + ExampleTarget, } #[deriving(Encodable, Decodable, Clone, PartialEq, Show)] @@ -328,7 +329,8 @@ impl> Encodable for Target { fn encode(&self, s: &mut S) -> Result<(), E> { let kind = match self.kind { LibTarget(ref kinds) => kinds.iter().map(|k| k.crate_type()).collect(), - BinTarget => vec!("bin") + BinTarget => vec!("bin"), + ExampleTarget => vec!["example"], }; SerializedTarget { @@ -457,7 +459,7 @@ impl Target { pub fn example_target(name: &str, src_path: &Path, profile: &Profile) -> Target { Target { - kind: BinTarget, + kind: ExampleTarget, name: name.to_string(), src_path: src_path.clone(), profile: profile.clone(), @@ -524,7 +526,7 @@ impl Target { } } - /// Returns true for binary, bench, tests and examples. + /// Returns true for binary, bench, and tests. pub fn is_bin(&self) -> bool { match self.kind { BinTarget => true, @@ -532,6 +534,14 @@ impl Target { } } + /// Returns true for exampels + pub fn is_example(&self) -> bool { + match self.kind { + ExampleTarget => true, + _ => false + } + } + pub fn get_profile(&self) -> &Profile { &self.profile } @@ -546,7 +556,8 @@ impl Target { LibTarget(ref kinds) => { kinds.iter().map(|kind| kind.crate_type()).collect() }, - BinTarget => vec!("bin") + ExampleTarget | + BinTarget => vec!("bin"), } } } diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index e3762012f..fb3886871 100644 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -225,7 +225,9 @@ impl<'a, 'b> Context<'a, 'b> { let stem = target.file_stem(); let mut ret = Vec::new(); - if target.is_bin() || target.get_profile().is_test() { + if target.is_example() { + ret.push(format!("examples/{}{}", stem, self.target_exe)); + } else if target.is_bin() || target.get_profile().is_test() { ret.push(format!("{}{}", stem, self.target_exe)); } else { if target.is_dylib() { diff --git a/src/cargo/ops/cargo_rustc/fingerprint.rs b/src/cargo/ops/cargo_rustc/fingerprint.rs index 4027d3a2f..1fd7b5534 100644 --- a/src/cargo/ops/cargo_rustc/fingerprint.rs +++ b/src/cargo/ops/cargo_rustc/fingerprint.rs @@ -87,7 +87,11 @@ pub fn prepare_target(cx: &mut Context, pkg: &Package, target: &Target, let (old_root, root) = { let layout = cx.layout(pkg, kind); - (layout.old_root().clone(), layout.root().clone()) + if target.is_example() { + (layout.old_examples().clone(), layout.examples().clone()) + } else { + (layout.old_root().clone(), layout.root().clone()) + } }; let mut pairs = vec![(old_loc, new_loc.clone())]; if !target.get_profile().is_doc() { diff --git a/src/cargo/ops/cargo_rustc/layout.rs b/src/cargo/ops/cargo_rustc/layout.rs index a9e9ca294..b2fd7bf88 100644 --- a/src/cargo/ops/cargo_rustc/layout.rs +++ b/src/cargo/ops/cargo_rustc/layout.rs @@ -11,6 +11,9 @@ //! # This is the root directory for all output of *dependencies* //! deps/ //! +//! # Root directory for all compiled examples +//! examples/ +//! //! # This is the location at which the output of all custom build //! # commands are rooted //! native/ @@ -44,6 +47,7 @@ //! # Same as the two above old directories //! old-native/ //! old-fingerprint/ +//! old-examples/ //! ``` use std::io::{mod, fs, IoResult}; @@ -57,11 +61,13 @@ pub struct Layout { deps: Path, native: Path, fingerprint: Path, + examples: Path, old_deps: Path, old_root: Path, old_native: Path, old_fingerprint: Path, + old_examples: Path, } pub struct LayoutProxy<'a> { @@ -88,10 +94,12 @@ impl Layout { deps: root.join("deps"), native: root.join("native"), fingerprint: root.join(".fingerprint"), + examples: root.join("examples"), old_deps: root.join("old-deps"), old_root: root.join("old-root"), old_native: root.join("old-native"), old_fingerprint: root.join("old-fingerprint"), + old_examples: root.join("old-examples"), root: root, } } @@ -101,31 +109,16 @@ impl Layout { try!(fs::mkdir_recursive(&self.root, io::USER_RWX)); } - if self.old_deps.exists() { - try!(fs::rmdir_recursive(&self.old_deps)); - } + try!(old(&[ + (&self.old_deps, &self.deps), + (&self.old_native, &self.native), + (&self.old_fingerprint, &self.fingerprint), + (&self.old_examples, &self.examples), + ])); + if self.old_root.exists() { try!(fs::rmdir_recursive(&self.old_root)); } - if self.old_native.exists() { - try!(fs::rmdir_recursive(&self.old_native)); - } - if self.old_fingerprint.exists() { - try!(fs::rmdir_recursive(&self.old_fingerprint)); - } - if self.deps.exists() { - try!(fs::rename(&self.deps, &self.old_deps)); - } - if self.native.exists() { - try!(fs::rename(&self.native, &self.old_native)); - } - if self.fingerprint.exists() { - try!(fs::rename(&self.fingerprint, &self.old_fingerprint)); - } - - try!(fs::mkdir(&self.deps, io::USER_RWX)); - try!(fs::mkdir(&self.native, io::USER_RWX)); - try!(fs::mkdir(&self.fingerprint, io::USER_RWX)); try!(fs::mkdir(&self.old_root, io::USER_RWX)); for file in try!(fs::readdir(&self.root)).iter() { @@ -134,11 +127,25 @@ impl Layout { try!(fs::rename(file, &self.old_root.join(file.filename().unwrap()))); } - Ok(()) + return Ok(()); + + fn old(dirs: &[(&Path, &Path)]) -> IoResult<()> { + for &(old, new) in dirs.iter() { + if old.exists() { + try!(fs::rmdir_recursive(old)); + } + if new.exists() { + try!(fs::rename(new, old)); + } + try!(fs::mkdir(new, io::USER_DIR)); + } + Ok(()) + } } pub fn dest<'a>(&'a self) -> &'a Path { &self.root } pub fn deps<'a>(&'a self) -> &'a Path { &self.deps } + pub fn examples<'a>(&'a self) -> &'a Path { &self.examples } pub fn native(&self, package: &Package) -> Path { self.native.join(self.pkg_dir(package)) } @@ -148,6 +155,7 @@ impl Layout { pub fn old_dest<'a>(&'a self) -> &'a Path { &self.old_root } pub fn old_deps<'a>(&'a self) -> &'a Path { &self.old_deps } + pub fn old_examples<'a>(&'a self) -> &'a Path { &self.old_examples } pub fn old_native(&self, package: &Package) -> Path { self.old_native.join(self.pkg_dir(package)) } @@ -166,6 +174,7 @@ impl Drop for Layout { let _ = fs::rmdir_recursive(&self.old_root); let _ = fs::rmdir_recursive(&self.old_native); let _ = fs::rmdir_recursive(&self.old_fingerprint); + let _ = fs::rmdir_recursive(&self.old_examples); } } @@ -182,12 +191,16 @@ impl<'a> LayoutProxy<'a> { } pub fn deps(&self) -> &'a Path { self.root.deps() } + pub fn examples(&self) -> &'a Path { self.root.examples() } + pub fn native(&self, pkg: &Package) -> Path { self.root.native(pkg) } pub fn old_root(&self) -> &'a Path { if self.primary {self.root.old_dest()} else {self.root.old_deps()} } + pub fn old_examples(&self) -> &'a Path { self.root.old_examples() } + pub fn old_native(&self, pkg: &Package) -> Path { self.root.old_native(pkg) } diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 45d51b9dc..ec34c060d 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -431,7 +431,11 @@ fn build_base_args(cx: &Context, fn build_plugin_args(mut cmd: ProcessBuilder, cx: &Context, pkg: &Package, target: &Target, kind: Kind) -> ProcessBuilder { cmd = cmd.arg("--out-dir"); - cmd = cmd.arg(cx.layout(pkg, kind).root()); + if target.is_example() { + cmd = cmd.arg(cx.layout(pkg, kind).examples()); + } else { + cmd = cmd.arg(cx.layout(pkg, kind).root()); + } let (_, dep_info_loc) = fingerprint::dep_info_loc(cx, pkg, target, kind); cmd = cmd.arg("--dep-info").arg(dep_info_loc); diff --git a/tests/test_cargo_compile.rs b/tests/test_cargo_compile.rs index afb48727d..e4abdd389 100644 --- a/tests/test_cargo_compile.rs +++ b/tests/test_cargo_compile.rs @@ -975,7 +975,7 @@ test!(many_crate_types_old_style_lib_location { let files = fs::readdir(&p.root().join("target")).assert(); let mut files: Vec = files.iter().filter_map(|f| { match f.filename_str().unwrap() { - "deps" => None, + "examples" | "deps" => None, s if s.contains("fingerprint") || s.contains("dSYM") => None, s => Some(s.to_string()) } @@ -1013,7 +1013,7 @@ test!(many_crate_types_correct { let files = fs::readdir(&p.root().join("target")).assert(); let mut files: Vec = files.iter().filter_map(|f| { match f.filename_str().unwrap() { - "deps" => None, + "examples" | "deps" => None, s if s.contains("fingerprint") || s.contains("dSYM") => None, s => Some(s.to_string()) } @@ -1280,8 +1280,10 @@ test!(explicit_examples { "#); assert_that(p.cargo_process("test"), execs()); - assert_that(process(p.bin("hello")), execs().with_stdout("Hello, World!\n")); - assert_that(process(p.bin("goodbye")), execs().with_stdout("Goodbye, World!\n")); + assert_that(process(p.bin("examples/hello")), + execs().with_stdout("Hello, World!\n")); + assert_that(process(p.bin("examples/goodbye")), + execs().with_stdout("Goodbye, World!\n")); }) test!(implicit_examples { @@ -1307,8 +1309,10 @@ test!(implicit_examples { "#); assert_that(p.cargo_process("test"), execs().with_status(0)); - assert_that(process(p.bin("hello")), execs().with_stdout("Hello, World!\n")); - assert_that(process(p.bin("goodbye")), execs().with_stdout("Goodbye, World!\n")); + assert_that(process(p.bin("examples/hello")), + execs().with_stdout("Hello, World!\n")); + assert_that(process(p.bin("examples/goodbye")), + execs().with_stdout("Goodbye, World!\n")); }) test!(standard_build_no_ndebug { diff --git a/tests/test_cargo_test.rs b/tests/test_cargo_test.rs index fd11bd361..34c045449 100644 --- a/tests/test_cargo_test.rs +++ b/tests/test_cargo_test.rs @@ -1150,3 +1150,32 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured ", compiling = COMPILING, running = RUNNING, dir = p.url(), doctest = DOCTEST).as_slice())); }) + +test!(example_bin_same_name { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + "#) + .file("src/bin/foo.rs", r#"fn main() { println!("bin"); }"#) + .file("examples/foo.rs", r#"fn main() { println!("example"); }"#); + + assert_that(p.cargo_process("test").arg("--no-run").arg("-v"), + execs().with_status(0) + .with_stdout(format!("\ +{compiling} foo v0.0.1 ({dir}) +{running} `rustc [..]bin[..]foo.rs [..] --test [..]` +{running} `rustc [..]bin[..]foo.rs [..]` +{running} `rustc [..]examples[..]foo.rs [..]` +", compiling = COMPILING, running = RUNNING, dir = p.url()).as_slice())); + + assert_that(&p.bin("foo"), existing_file()); + assert_that(&p.bin("examples/foo"), existing_file()); + + assert_that(p.process(p.bin("foo")), + execs().with_status(0).with_stdout("bin\n")); + assert_that(p.process(p.bin("examples/foo")), + execs().with_status(0).with_stdout("example\n")); +}) -- 2.30.2